package wili.json;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Predicate;

import wili.c.Ca;
import wili.c.File9a;
import wili.c.Misc9a;
import wili.c.Str9a;

/**
 * File which name ends with ".json"
 */
@SuppressWarnings("unchecked")
public class JsonFile0 {
	public final File file;
	public final String fileSt;
	public final int length;
	public final JsonObj root;
	final Str9a.IndMap indMap;
	final Map<String, JsonObj> guidMap = new HashMap<>();
	public int[] updateTimes = { 0 };
	final List<Integer> lineInds;

	public String toString() {
		return "JsonFile:" + file.getName();
	}

	public static void main(String[] args) {
		int opt = 1;
		opt = 2;
		if (opt == 1) {
			replaceGuid_demo();
		} else if (opt == 2) {
			test();
		}
	}

	public void print(int opt) {
		if (opt < 0)
			return;
		StringBuilder sb = new StringBuilder();
		sb.append("\n==============jsonFile: " + file.getName());
		root.print("\n", sb);
		Ca.log(1, sb);
	}

	public JsonFile0(String jsonSt) {
		this(null, jsonSt);
	}

	public JsonFile0(File jsonFile) {
		this(jsonFile, "");
	}

	protected JsonFile0(File jsonFile, String jsonSt) {
		this.file = jsonFile;
		if (jsonSt.isEmpty()) {
			jsonSt = File9a.strOfFile(jsonFile, "");
			if (jsonSt.isEmpty()) {
				fileSt = "";
				lineInds = null;
				indMap = null;
				length = 0;
				root = null;
				throw Ca.newRuntimeException("error: Empty file: " + jsonFile.getName());
			}
		} else {
		}
		fileSt = jsonSt;
		lineInds = Misc9a.indexListOfLines(fileSt);
		length = fileSt.length();
		int startInd = Str9a.indexOfAnyChar(fileSt, 0, '{')[0];
		indMap = Str9a.readBracketIndMap(fileSt, startInd, true);
		this.root = new JsonObj(this, startInd, null);
	}

	public String refreshJsonSt() {
		StringBuilder sb = new StringBuilder((int) (fileSt.length() * 1.1));
		root.saveToBuffer("\n", sb);
		String st = sb.toString();
		{
			st = st.replace("{i18n#", "{i18n>");
			st = st.replaceAll(":\\s*\"(true|false)\"", ": $1");
		}
		// this.fileSt = st;
		return st;
	}

	public <T extends JsonNode> List<T> findNodesByPath(Object... path) {
		List<T> toList = this.root.findNodesByPath(path);
		return toList;
	}

	public <T extends JsonNode> List<T> findNodesByName(String name) {
		return findNodes(new Predicate<JsonNode>() {
			// @Override
			public boolean test(JsonNode nod) {
				if (name.equals(nod.attName))
					return true;
				return false;
				// if (nod instanceof JsonAtt__) {
				// JsonAtt__ att = (JsonAtt__) nod;
				// if (att.name.equals(name))
				// return true;
				// }
				// return false;
			}
		});
	}

	public <T extends JsonNode> List<T> findNodes(Predicate<JsonNode> pred) {
		return (List<T>) root.findNodes(true, pred);
	}

	public <T extends JsonNode> T findObj_byAtt(String att, String valueSt) {
		return (T) root.findObjByAtt(att, valueSt);
	}

	public <T extends JsonObj> List<T> findObjs_byAtt(String att, String valueSt) {
		return (List<T>) root.findObjsByAtt(true, att, valueSt);
	}

	public <T extends JsonNode> List<String> findAttStringValues__(String name, String value, Function<T, String> fun) {
		return root.findAttStringValues(name, value, fun);
	}

	public static void replaceGuid_demo() {
		File file1 = null, file2 = null;
		int opt = 1;
		if (opt == 1) {
			file1 = new File(
					"C:\\Perforce\\c1816431\\BUSMB_B1\\SBO\\dev\\Source\\WebClient\\java\\tcli\\tcli-resources\\src\\main\\resources\\detailView\\SalesDoc.detailView_acc.json");
			file2 = new File(
					"C:\\Perforce\\c1816431\\BUSMB_B1\\SBO\\dev\\Source\\WebClient\\java\\tcli\\tcli-resources\\target\\classes\\detailView\\SalesDoc.detailView.json");
		} else if (opt == 2) {
		}
		// File file = new File("D:\\bearJ\\awilly\\t\\json_demo\\t.json");
		JsonFile0 json = new JsonFile0(file1);
		JsonFile0 json2 = new JsonFile0(file2);
		json.print(-1);
		{// test
			String guid = "c705786f-8d01-414a-aefc-819c2c615a45,weilai";
			JsonObj ret = json.guidMap.get(guid);
			JsonObj ret2 = json2.guidMap.get(guid);
			String toFileSt = json2.fileSt.substring(0, ret2.startInd) + ret.getString(false)
					+ json2.fileSt.substring(ret2.endInd);
			if ("".isEmpty()) {
				File9a.str2file(toFileSt, file2, -1);
				Ca.log("File updated: " + file2.getName());
			}
		}
	}

	// @Override
	public void saveToFile(File toFile, Function<String, String> fun) {
		if (toFile == null)
			toFile = this.file;
		String retSt = this.refreshJsonSt();
		if (fun != null)
			retSt = fun.apply(retSt);
		if (false)
			retSt = retSt.replaceAll("\\$\\{ObjType\\}\\s*===\\s*(-?\\d+)", "\\$\\{ObjType\\} === '$1'");
		File9a.str2file(retSt, toFile, -1);
		if ("asdf".isEmpty())
			Ca.log(1, "\n JsonFile.saveToFile: " + toFile.getName());
	}

	public static void test() {
		File file2 = new File("C:\\bearJ\\awilly\\src\\main\\java\\wili\\misc\\SalesDoc.detailView.json");
		JsonFile0 json2 = new JsonFile0(file2);
		json2.print(-1);
		{// test findObjs
			JsonObj ret = json2.guidMap.get("37167663-f5e9-444a-90db-886631a401af");
			Ca.log(1, "found1: " + ret);
			List<JsonObj> lis = json2.findObjs_byAtt("bind", "VAttachmentList");
			Ca.log(1, "found2: " + lis.size() + lis);
		}
	}

	// @Override
	public File file() {
		return this.file;
	}

	public Map<String, List<JsonNode>> findNodeMap_mathPath(Map<String, List<JsonNode>> toMap, String idAtt,
			String... path) {
		if (toMap == null)
			toMap = new HashMap<>();
		root.findNodeMap_mathPath(toMap, idAtt, path);
		return toMap;
	}

	// @Override
	public int[] getUpdateTimes() {
		return this.updateTimes;
	}
}
